package com.leyou.search.service.impl;

import com.leyou.common.exception.LyException;
import com.leyou.item.clients.ItemClient;
import com.leyou.search.dto.SearchDTO;
import com.leyou.search.entity.Goods;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.service.SearchService;
import com.leyou.starter.elastic.entity.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.Nested;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private GoodsRepository repository;
    @Autowired
    private ItemClient itemClient;

    @Override
    public Mono<List<String>> suggestion(String key) {
        //异步自动匹配  匹配成功后结果封装到mono中  需要从mono中值获取存入list中
        Mono<List<String>>suggestion=repository.suggestBySingleField("suggestion",key);
        return suggestion;
    }

    @Override
    public Mono<PageInfo<Goods>> listData(SearchDTO searchDTO) {
        //武大
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        //获取查询条件封装对象
        QueryBuilder query=buildQuery(searchDTO);
        //添加查询条件
        sourceBuilder.query(query);
        Integer from=(searchDTO.getPage()-1)*searchDTO.getSIZE();
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.preTags("<em>");
        highlightBuilder.postTags("</em>");
        highlightBuilder.field("title");

        sourceBuilder.highlighter(highlightBuilder);

        return repository.queryBySourceBuilderForPageHighlight(sourceBuilder);
    }

    @Override
    public Mono<Map<String, List<?>>> listFilter(SearchDTO searchDTO) {

        //武大
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //添加查询条件
        sourceBuilder.query(buildQuery(searchDTO));
        //添加聚合条件
        //对品牌聚合
        sourceBuilder.aggregation(AggregationBuilders.terms("brandAgg").field("brandId"));

        //对分类聚合
        sourceBuilder.aggregation(AggregationBuilders.terms("categoryAgg").field("categoryId"));

        //对规格参数进行聚合
        sourceBuilder.aggregation(
                AggregationBuilders.nested("specAgg", "specs")
                        .subAggregation(AggregationBuilders.terms("nameAgg").field("specs.name")
                                .subAggregation(AggregationBuilders.terms("valueAgg").field("specs.value")))
        );


        //查询聚合
        Mono<Aggregations> aggregationsMono = repository.aggregationBySourceBuilder(sourceBuilder);

        //解析聚合
        return aggregationsMono.map(aggregations -> {

            Map<String, List<?>> result = new LinkedHashMap<>();


            Terms categoryAgg = aggregations.get("categoryAgg");

            List<Long> categoryIds = categoryAgg.getBuckets()
                    .stream()
                    .map(Terms.Bucket::getKeyAsNumber)
                    .map(Number::longValue)
                    .collect(Collectors.toList());

            //判断id集合是否为空
            if (CollectionUtils.isEmpty(categoryIds)) {
                result.put("分类", new ArrayList<>());
            } else {
                result.put("分类", this.itemClient.queryCategoryByIds(categoryIds));
            }


            Terms brandAgg = aggregations.get("brandAgg");

            List<Long> brandIds = brandAgg.getBuckets()
                    .stream()
                    .map(Terms.Bucket::getKeyAsNumber)
                    .map(Number::longValue)
                    .collect(Collectors.toList());

            //判断id集合是否为空
            if (CollectionUtils.isEmpty(brandIds)) {
                result.put("品牌", new ArrayList<>());
            } else {
                result.put("品牌", this.itemClient.queryBrandByIds(brandIds));
            }


            //获取到规格参数的nested聚合
            Nested specAgg = aggregations.get("specAgg");

            //从nested聚合中获取到nameAgg聚合
            Terms nameAgg = specAgg.getAggregations().get("nameAgg");

            //获取其聚合内容
            nameAgg.getBuckets()
                    .stream()
                    .forEach(bucket -> {
                        //获取聚合的key
                        String key = ((Terms.Bucket) bucket).getKeyAsString();

                        //获取子聚合
                        Terms valueAgg = ((Terms.Bucket) bucket).getAggregations().get("valueAgg");

                        //从子聚合中获取聚合结果
                        List<String> values = valueAgg
                                .getBuckets()
                                .stream()
                                .map(Terms.Bucket::getKeyAsString)
                                .collect(Collectors.toList());
                        result.put(key, values);
                    });

            return result;
        });

    }

    private QueryBuilder buildQuery(SearchDTO searchDTO) {
        String key=searchDTO.getKey();
        //进行数据的基本校验处理
        if (StringUtils.isEmpty(key)){
            throw new LyException(400,"请求参数封装有误，查询key不能为空");
        }
        Integer page=searchDTO.getPage();
        if (null==page||page<1){
            page=1;
        }
        return QueryBuilders.matchQuery("title",key).operator(Operator.AND);
    }
}
